/*-------------------------------------------------------------------------
 *
 * standbydesc.c
 *	  用于 storage/ipc/standby.c 的 rmgr 描述符例程
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *	  src/backend/access/rmgrdesc/standbydesc.c
 *
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

#include "storage/standbydefs.h"

static void fc_standby_desc_running_xacts(StringInfo fc_buf, xl_running_xacts *fc_xlrec)
{
	int			fc_i;

	appendStringInfo(fc_buf, "nextXid %u latestCompletedXid %u oldestRunningXid %u",
					 fc_xlrec->nextXid,
					 fc_xlrec->latestCompletedXid,
					 fc_xlrec->oldestRunningXid);
	if (fc_xlrec->xcnt > 0)
	{
		appendStringInfo(fc_buf, "; %d xacts:", fc_xlrec->xcnt);
		for (fc_i = 0; fc_i < fc_xlrec->xcnt; fc_i++)
			appendStringInfo(fc_buf, " %u", fc_xlrec->xids[fc_i]);
	}

	if (fc_xlrec->subxid_overflow)
		appendStringInfoString(fc_buf, "; subxid ovf");
}

void standby_desc(StringInfo fc_buf, XLogReaderState *fc_record)
{
	char	   *fc_rec = XLogRecGetData(fc_record);
	uint8		fc_info = XLogRecGetInfo(fc_record) & ~XLR_INFO_MASK;

	if (fc_info == XLOG_STANDBY_LOCK)
	{
		xl_standby_locks *fc_xlrec = (xl_standby_locks *) fc_rec;
		int			fc_i;

		for (fc_i = 0; fc_i < fc_xlrec->nlocks; fc_i++)
			appendStringInfo(fc_buf, "xid %u db %u rel %u ",
							 fc_xlrec->locks[fc_i].xid, fc_xlrec->locks[fc_i].dbOid,
							 fc_xlrec->locks[fc_i].relOid);
	}
	else if (fc_info == XLOG_RUNNING_XACTS)
	{
		xl_running_xacts *fc_xlrec = (xl_running_xacts *) fc_rec;

		fc_standby_desc_running_xacts(fc_buf, fc_xlrec);
	}
	else if (fc_info == XLOG_INVALIDATIONS)
	{
		xl_invalidations *fc_xlrec = (xl_invalidations *) fc_rec;

		standby_desc_invalidations(fc_buf, fc_xlrec->nmsgs, fc_xlrec->msgs,
								   fc_xlrec->dbId, fc_xlrec->tsId,
								   fc_xlrec->relcacheInitFileInval);
	}
}

const char * standby_identify(uint8 fc_info)
{
	const char *fc_id = NULL;

	switch (fc_info & ~XLR_INFO_MASK)
	{
		case XLOG_STANDBY_LOCK:
			fc_id = "LOCK";
			break;
		case XLOG_RUNNING_XACTS:
			fc_id = "RUNNING_XACTS";
			break;
		case XLOG_INVALIDATIONS:
			fc_id = "INVALIDATIONS";
			break;
	}

	return fc_id;
}

/*
 * 这个例程被 standby_desc 和 xact_desc 使用，因为
 * 事务提交和 XLOG_INVALIDATIONS 消息包含无效消息；
 * 复制代码似乎没有意义。
 */
void standby_desc_invalidations(StringInfo fc_buf,
						   int fc_nmsgs, SharedInvalidationMessage *fc_msgs,
						   Oid fc_dbId, Oid fc_tsId,
						   bool fc_relcacheInitFileInval)
{
	int			fc_i;

	/* 如果没有无效消息则不做任何操作 */
	if (fc_nmsgs <= 0)
		return;

	if (fc_relcacheInitFileInval)
		appendStringInfo(fc_buf, "; relcache init file inval dbid %u tsid %u",
						 fc_dbId, fc_tsId);

	appendStringInfoString(fc_buf, "; inval msgs:");
	for (fc_i = 0; fc_i < fc_nmsgs; fc_i++)
	{
		SharedInvalidationMessage *fc_msg = &fc_msgs[fc_i];

		if (fc_msg->id >= 0)
			appendStringInfo(fc_buf, " catcache %d", fc_msg->id);
		else if (fc_msg->id == SHAREDINVALCATALOG_ID)
			appendStringInfo(fc_buf, " catalog %u", fc_msg->cat.catId);
		else if (fc_msg->id == SHAREDINVALRELCACHE_ID)
			appendStringInfo(fc_buf, " relcache %u", fc_msg->rc.relId);
		/* 不太可能，但还是打印一些内容 */
		else if (fc_msg->id == SHAREDINVALSMGR_ID)
			appendStringInfoString(fc_buf, " smgr");
		/* 不太可能，但还是打印一些内容 */
		else if (fc_msg->id == SHAREDINVALRELMAP_ID)
			appendStringInfo(fc_buf, " relmap db %u", fc_msg->rm.dbId);
		else if (fc_msg->id == SHAREDINVALSNAPSHOT_ID)
			appendStringInfo(fc_buf, " snapshot %u", fc_msg->sn.relId);
		else
			appendStringInfo(fc_buf, " unrecognized id %d", fc_msg->id);
	}
}
